package com.jorado.core.concurrent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * @Auther: len.zhang
 * @Date: 2019/6/19 11:15
 * @Description:
 */
public class ParallelExecuter<T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(ParallelExecuter.class);

    private List<Future<T>> futures;
    private ExecutorService executor;

    public ParallelExecuter(ExecutorService executor) {
        this.executor = executor;
        this.futures = new ArrayList<>();
    }

    public ParallelExecuter add(Callable<T> callable) {
        RunnableFuture<T> runnableFuture = new FutureTask<>(callable);
        this.executor.execute(runnableFuture);
        this.futures.add(runnableFuture);
        return this;
    }

    public List<T> get() {
        List<T> futureResults = new ArrayList<>();
        futures.forEach(n -> {
            try {
                futureResults.add(n.get());
            } catch (Exception ex) {
                LOGGER.error("ParallelExecuter error", ex);
            }
        });
        this.reset();
        return futureResults;
    }

    public <R> List<R> get(Function<T, R> callback) {
        List<R> futureResults = new ArrayList<>();
        futures.forEach(n -> {
            try {
                futureResults.add(callback.apply(n.get()));
            } catch (Exception ex) {
                LOGGER.error("ParallelExecuter with callback error", ex);
            }
        });
        this.reset();
        return futureResults;
    }

    public ParallelExecuter reset() {
        this.futures.clear();
        return this;
    }

    public int size() {
        return futures.size();
    }
}